﻿#if NET35
//为接口统一,定义与 netstandard2.0环境下Microsoft.Extensions.DependencyInjection.IServiceCollection 相同的接口及操作    
using System;
namespace Kernelx.Common.DependencyInjection
{
    /// <summary>
    /// 
    /// </summary>
    public static class ServiceCollectionServiceExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationType"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, Type implementationType)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            if (implementationType == null)
            {
                throw new ArgumentNullException("implementationType");
            }

            return Add(services, serviceType, implementationType, ServiceLifetime.Transient);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationFactory"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, Func<IServiceProvider, object> implementationFactory)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            if (implementationFactory == null)
            {
                throw new ArgumentNullException("implementationFactory");
            }

            return Add(services, serviceType, implementationFactory, ServiceLifetime.Transient);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TImplementation"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddTransient<TService, TImplementation>(this IServiceCollection services) where TService : class where TImplementation : class, TService
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            return services.AddTransient(typeof(TService), typeof(TImplementation));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            return services.AddTransient(serviceType, serviceType);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddTransient<TService>(this IServiceCollection services) where TService : class
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            return services.AddTransient(typeof(TService));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationType"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddScoped(this IServiceCollection services, Type serviceType, Type implementationType)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            if (implementationType == null)
            {
                throw new ArgumentNullException("implementationType");
            }

            return Add(services, serviceType, implementationType, ServiceLifetime.Scoped);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationFactory"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddScoped(this IServiceCollection services, Type serviceType, Func<IServiceProvider, object> implementationFactory)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            if (implementationFactory == null)
            {
                throw new ArgumentNullException("implementationFactory");
            }

            return Add(services, serviceType, implementationFactory, ServiceLifetime.Scoped);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TImplementation"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddScoped<TService, TImplementation>(this IServiceCollection services) where TService : class where TImplementation : class, TService
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            return services.AddScoped(typeof(TService), typeof(TImplementation));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddScoped(this IServiceCollection services, Type serviceType)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            return services.AddScoped(serviceType, serviceType);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddScoped<TService>(this IServiceCollection services) where TService : class
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            return services.AddScoped(typeof(TService));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationType"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, Type implementationType)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            if (implementationType == null)
            {
                throw new ArgumentNullException("implementationType");
            }

            return Add(services, serviceType, implementationType, ServiceLifetime.Singleton);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationFactory"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, Func<IServiceProvider, object> implementationFactory)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            if (implementationFactory == null)
            {
                throw new ArgumentNullException("implementationFactory");
            }

            return Add(services, serviceType, implementationFactory, ServiceLifetime.Singleton);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TImplementation"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection services) where TService : class where TImplementation : class, TService
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            return services.AddSingleton(typeof(TService), typeof(TImplementation));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            return services.AddSingleton(serviceType, serviceType);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton<TService>(this IServiceCollection services) where TService : class
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            return services.AddSingleton(typeof(TService));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="services"></param>
        /// <param name="implementationFactory"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (implementationFactory == null)
            {
                throw new ArgumentNullException("implementationFactory");
            }

            return services.AddSingleton(typeof(TService), implementationFactory);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TImplementation"></typeparam>
        /// <param name="services"></param>
        /// <param name="implementationFactory"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection services, Func<IServiceProvider, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (implementationFactory == null)
            {
                throw new ArgumentNullException("implementationFactory");
            }

            return services.AddSingleton(typeof(TService), implementationFactory);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceType"></param>
        /// <param name="implementationInstance"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, object implementationInstance)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException("serviceType");
            }

            if (implementationInstance == null)
            {
                throw new ArgumentNullException("implementationInstance");
            }

            ServiceDescriptor item = new ServiceDescriptor(serviceType, implementationInstance);
            services.Add(item);
            return services;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="services"></param>
        /// <param name="implementationInstance"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddSingleton<TService>(this IServiceCollection services, TService implementationInstance) where TService : class
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }

            if (implementationInstance == null)
            {
                throw new ArgumentNullException("implementationInstance");
            }

            return services.AddSingleton(typeof(TService), implementationInstance);
        }

        private static IServiceCollection Add(IServiceCollection collection, Type serviceType, Type implementationType, ServiceLifetime lifetime)
        {
            ServiceDescriptor item = new ServiceDescriptor(serviceType, implementationType, lifetime);
            collection.Add(item);
            return collection;
        }

        private static IServiceCollection Add(IServiceCollection collection, Type serviceType, Func<IServiceProvider, object> implementationFactory, ServiceLifetime lifetime)
        {
            ServiceDescriptor item = new ServiceDescriptor(serviceType, implementationFactory, lifetime);
            collection.Add(item);
            return collection;
        }
    }

}

#endif